from .gui import *

class ModelListPanelControl(ModelListPanelGUI):

    def __init__(self, parent=None):
        super().__init__(parent=parent)

    def _init_tree_data(self):
        '''初始化目录树结构'''
        self.root = self.treeCtrl.AddRoot('Model&Entity')
        self.treeCtrl.SetItemData(self.root, None)
        self.treeCtrl.SetItemImage(self.root, self.fldridx, wx.TreeItemIcon_Normal)
        self.treeCtrl.SetItemImage(self.root, self.fldropenidx, wx.TreeItemIcon_Expanded)

        self.tree_apps_models_struct = model_datas = djangotools.get_all_models_link_app_path()
        for model_data in model_datas:
            app_node = self.treeCtrl.AppendItem(self.root, model_data[0])
            self.treeCtrl.SetItemData(app_node, None)
            self.treeCtrl.SetItemImage(app_node, self.fldridx, wx.TreeItemIcon_Normal)
            self.treeCtrl.SetItemImage(app_node, self.fldropenidx, wx.TreeItemIcon_Expanded)

            for _ in model_data[1]:
                t_node = self.treeCtrl.AppendItem(app_node, _)
                self.treeCtrl.SetItemData(t_node, None)
                self.treeCtrl.SetItemImage(t_node, self.fileidx, wx.TreeItemIcon_Normal)
                self.treeCtrl.SetItemImage(t_node, self.infoidx, wx.TreeItemIcon_Selected)

        # self.treeCtrl.Expand(self.root)
        self.treeCtrl.ExpandAll()

    def _get_key_from_name_by_nodes(self, field_types: List[Tuple[str]], node_name: str) -> str:
        '''通过类型中文名，获取类型英文名
        
            未找到匹配项将返回 None
        '''
        real_name = node_name.split('-')[1]
        for e_name, c_name in field_types:
            if c_name == real_name:
                return e_name
        return None # 理论上一定会找到，不存在返回 None 的情况

    def _get_bulid_data(self, ori_datas: Dict[str, Any], isHand: bool, unshowSpace: bool=False) -> List[Any]:
        '''构建树形列表数据
        
            触发型构建
            ori_datas: 初始的数据包
            isHand: 双击节点才会显示
            unshowSpace: 对于没有使用的字段类型进行隐藏
        '''
        if not isHand: return [] # 不允许界面自动更新

        self.treeListData.ClearColumns() ### 每次新构建时均清空之前的所有数据

        '''
            所有未被遗弃且可使用的字段类型中文名（name）
        '''
        field_types: List[Tuple[str]] = [_ for _ in model_type_data.get_all_field_types_by_key('name') if _] # 系统内置所有的类型
        type_names = [_.get('type_name') for _ in ori_datas.values()] # 数据包中包含的数据类型【允许重复，计数用】
        nodes: List[FieldType] = [] # 所有的主节点构建
        for field_type in field_types:
            '''
                如果有数量，则在字段类型名前面加上 '[0]-' 之类的前缀符号，方便使用者阅读和标记
                field_type 为一个二元组，第一个元素是 CharField 之类的，第二个元素是 字符型 之类的。
            '''
            count_fields = type_names.count(field_type[0]) # 统计该字段类型下的所有字段数
            if unshowSpace and 0 == count_fields:
                continue
            nodes.append(FieldType(f'[{count_fields}]-{field_type[1]}')) # 中文名称
        nodes.sort(key=lambda x: x.name, reverse=True) # 按该类型下的字段个数倒序排序
        
        '''
            解析数据包不为空时，尝试解析数据
        '''
        for k, v in ori_datas.items():
            type_name = v["type_name"]
            options: Dict[str, Any] = v["options"]
            '''
                寻找待插入的节点
            '''
            for n in nodes: # 一定能够全部匹配（除非出现非内置类型之外的自定义字段类型）
                if self._get_key_from_name_by_nodes(field_types, n.name) == type_name:
                    '''
                        因为 ShowModelsModel 中已经对值进行了排列，这里就不再按顺序插值
                        一行，先赋值默认值，后按需改值
                    '''
                    field = Field(n.name)
                    # 默认值填充【先默认，后特殊的原则】
                    for _k, _v in model_type_data.read_field_options().items():
                        if _v['type'] in ('EnumProperty'):
                            setattr(field, _k, str([]))
                        else:
                            setattr(field, _k, str(_v.get('default')))
                    '''
                        每个字段的真实选项值填写（解析 options）
                    '''
                    # 如果没有提供 verbose_name 和 db_column，则默认取 k【verbose_name下划线替换成空格】
                    if options.get('verbose_name') is None:
                        setattr(field, 'verbose_name', k.replace('_', ' '))
                    if options.get('db_column') is None:
                        setattr(field, 'db_column', k)
                    for _k, _v in options.items():
                        setattr(field, _k, str(_v))
                    n.fields.append(field)
                    break # 逻辑上不可能重复

        return nodes

    def _init_listree_data(self, ori_datas: Dict[str, Any]=None, isHand: bool = False, select_model_name: str = '[未选择]', unshowSpace: bool=False, context: Dict[str, Any] = None):
        """初始化树形列表"""
        '''
            数据包构建的顺序，以 option_names 的顺序为标准
        '''
        if context is not None:
            context[CONTEXT_REF_TREELIST] = True ### 锁定操作
        option_names: List[Tuple[str]] = model_type_data.get_all_field_options_by_key('name')

        '''
            数据包构建
        '''
        data = self._get_bulid_data(ori_datas, isHand, unshowSpace)
        self.model = ShowModelsModel(data, option_names) # 第二个参数，确保显示顺序的一致性
        self.treeListData.AssociateModel(self.model) # 通知控件使用该模型
        self.model.DecRef() # 渲染

        '''
            初始化列
        '''
        tr = wxdv.DataViewTextRenderer()
        col0 = wxdv.DataViewColumn(f"{select_model_name}的字段类型", tr, 0)
        self.treeListData.AppendColumn(col0)
        col0.SetWidth(160)
        col0.SetAlignment(wx.ALIGN_LEFT)

        insert_columns = []
        for option_name in option_names:
            insert_columns.append(
                (option_name[1], 88, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn)
            )
        insert_columns.append(
            # 末尾加一列空列（解决列表展示最后一列无法正常显示的BUG）
            ("", 1, wxdv.DATAVIEW_CELL_ACTIVATABLE, wx.ALIGN_CENTER, self.treeListData.AppendTextColumn)
        )
        
        self._list_append_columns(insert_columns)

        # 允许排序
        for c in self.treeListData.Columns:
            c.Sortable = True
            c.Reorderable = True

        if context is not None:
            context[CONTEXT_REF_TREELIST] = False ### 解锁

    def _list_append_columns(self, columns: List[object]):
        """列表添加列（从第二列开始自动添加）"""
        begin_index = 1
        for col in columns:
            col[-1](col[0], begin_index, width=col[1], mode=col[2], align=col[3])
            begin_index += 1
